#pragma once

#include <string>
#include <functional>

#include <cstdlib>

#include <unistd.h>
#include <signal.h>

#include "socket.hpp"
#include "Daemon.hpp"
#include "log.hpp"

extern Log log;

class TCPServer
{
public:
    typedef std::function<std::string(std::string&)> func_t;

    TCPServer(uint16_t port, func_t callback, const std::string& ip = "0.0.0.0")
        : _listen_socket(AF_INET)
        , _port(port)
        , _ip(ip)
        , _callback(callback)
    {}

    bool server_init()
    {
#ifdef __TEST__DEBUG__
        signal(SIGCHLD, SIG_IGN);
#else
        log.change_method(Class);
        Daemon();
#endif
        _listen_socket.Create(SOCK_STREAM);
        _listen_socket.Bind(_port, _ip);
        _listen_socket.Listen();
    }
    void start()
    {
        while (true)
        {
            std::string clientip;
            uint16_t clientport;
            int sockfd = _listen_socket.Accept(clientip, clientport);
            if (sockfd < 0)
                continue;
            
            // 多进程完成服务
            if (fork() == 0)
            {
                _listen_socket.Close();
                std::string req_stream;
                while (true)
                {
                    char buffer[1024];
                    ssize_t n = read(sockfd, buffer, sizeof(buffer) - 1);
                    if (n > 0)
                    {
                        buffer[n] = 0;
                        req_stream += buffer;
#ifdef __TEST__DEBUG__
                        log(Info, "client request: %s, sockfd: %d, clientip: %s, clientport: %d", req_stream.c_str(), sockfd, clientip.c_str(), clientport);
#endif
                        while (true)
                        {
                            std::string resp_stream = _callback(req_stream);
                            if (resp_stream.empty())
                                break;
                            n = write(sockfd, resp_stream.c_str(), resp_stream.size()); 
                            if (n < 0)
                            {
                                log(Warning, "write error, sockfd: %d, clientip: %s, clientport: %d, errno: %d, errstring: %s", sockfd, clientip.c_str(), clientport, errno, strerror(errno));
                                break;
                            }
#ifdef __TEST__DEBUG__
                            log(Info, "server response: %s, sockfd: %d, clientip: %s, clientport: %d", resp_stream.c_str(), sockfd, clientip.c_str(), clientport);
#endif
                        }
                    }
                    else if (n == 0)
                    {
                        log(Info, "%s:%d quit, server close sockfd: %d", clientip.c_str(), clientport, sockfd);
                        break;
                    }
                    else
                    {
                        log(Warning, "read error, sockfd: %d, clientip: %s, clientport: %d, errno: %d, errstring: %s", sockfd, clientip.c_str(), clientport, errno, strerror(errno));
                        break;
                    }
                }
                close(sockfd);
                exit(0);
            }

        }
    }

    ~TCPServer()
    {
        _listen_socket.Close();
    }
private:
    Socket _listen_socket;
    uint16_t _port;
    std::string _ip;
    func_t _callback;
};